package dl64507

import (
	"bytes"
	"fmt"
	"strconv"
	"szkis/simu/utils"
	"szkis/wrap/lg"
	"time"
)

type DataResult struct {
	Data 	float64
	TurnResult 	bool
	Flag 	bool 	// 解包成功标志 false为失败
	DeviceCode string
	DataType	int  // 0=读表 1=拉合闸 2=电流
	Ia float64	// A相电流
	Ib float64	// B相电流
	Ic float64 	// C相电流
}

// 正向有功
var DATA_0010 = []byte{0x68, 0x11, 0x04, 0x33, 0x33, 0x34, 0x33}
// 组合有功
var DATA_0000 = []byte{0x68, 0x11, 0x04, 0x33, 0x33, 0x33, 0x33}
// 电流数据块
var DATA_22F0 = []byte{0x68, 0x11, 0x04, 0x33, 0x32, 0x35, 0x35}

// 单相表可跳闸，三相表不行【国网？】
// 合闸
var TURN_ON_CL = []byte{0x68, 0x1c, 0x10, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x4f, 0x33}
// 跳闸
var TURN_OFF_CL = []byte{0x68, 0x1c, 0x10, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x4d, 0x33}


// 单相表和三相表， 均可跳闸和合闸
// 合闸
var TURN_ON = []byte{0x68, 0x1c, 0x10, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x4e, 0x33}
// 跳闸
var TURN_OFF = []byte{0x68, 0x1c, 0x10, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x4d, 0x33}

// 读取 0010 的报文【正向有功】
func ReadPacket0010(addr string) []byte {
	return buildPacket(addr, DATA_0010)
}

// 读取 0000 的报文 【组合有功】
func ReadPacket0000(addr string) []byte {
	return buildPacket(addr, DATA_0000)
}

// 读取 0f22 的报文【电流】
func ReadPacket0F22(addr string) []byte {
	return buildPacket(addr, DATA_22F0)
}

// 合闸报文
func TurnOnPacket(addr string) []byte{
	buf := bytes.Buffer{}
	buf.Write(TURN_ON)
	buf.Write(fmt_ssmmhhddmmyy())

	// CL 没作用
	if addr[0:2] == "04" {
		buf = bytes.Buffer{}
		buf.Write(TURN_ON_CL)
		buf.Write(fmt_ssmmhhddmmyy())
	}

	lg.Debug(utils.BytesToHex(buildPacket(addr, buf.Bytes())))
	return buildPacket(addr, buf.Bytes())
}

// 跳闸报文
func TurnOffPacket(addr string) []byte{
	buf := bytes.Buffer{}
	buf.Write(TURN_OFF)
	buf.Write(fmt_ssmmhhddmmyy())

	lg.Debug(utils.BytesToHex(buildPacket(addr, buf.Bytes())))
	return buildPacket(addr, buf.Bytes())
}

func fmt_ssmmhhddmmyy() []byte{
	// ssmmHHddMMyy
	// 06-01-02 15:04:05
	dt := time.Now().Add(time.Hour * 1).Format("050415020106")
	data := utils.HexToBytes(dt)
	for n, _ := range data {
		data[n] = data[n] + 0x33
	}
	return data
}

func ParsePacket(bs []byte) DataResult {
	ret := DataResult{
		Flag : false, 
	}

	// 去掉前导FE
	data := utils.ClearFE(bs)
	// 1. 报文字节少于8
	if len(data) < 8 {
		return ret
	}
	
	// 地址
	ret.DeviceCode = utils.BytesToHex(utils.BytesReverse(data[1:7]))
	
	// 2. 拉闸或合闸【成功】
	if data[8] == 0x9c {
		ret.TurnResult = true 
		ret.Flag = true 
		ret.DataType = 1
		return ret 
	}

	// 2. 拉闸或合闸【失败】
	if data[8] == 0xdc {
		ret.TurnResult = false 
		ret.Flag = true 
		ret.DataType = 1 
		return ret 
	}

	// 3. 读表成功 6844680029101868910933333433【8B8B6745】362C16
	if data[8] == 0x91 && len(data) > 19 {
		// 68 34 12 01 20 06 22 68 91 0E 33 32 35 35 33 33 43 33 33 43 33 33 43 35 FD 16  
		// 电流数据块
		if data[9] == 0x0E {
			ret.Flag = true
			ret.DataType = 2
			ret.Ia = currentBlock(data[14:17])
			ret.Ib = currentBlock(data[17:20])
			ret.Ic = currentBlock(data[20:23])
			return ret
		}
		ret.Flag = true
		ret.DataType = 0
		ret.Data = MeterValue(data[14:18])
	}
	
	return ret
}

func currentBlock(bs []byte) float64 {
	// 电流数据块
	var ret float64 = 0.00
	// 1. 翻转
	data := utils.BytesReverse(bs)
	// 2. BCD转码
	for n, _ := range data {
		data[n] = data[n] - 0x33
	}
	// 3. 转hex
	valStr := utils.BytesToHex(data)
	// 4. 转整数
	num, err := strconv.Atoi(valStr)
	if err != nil {
		return ret 
	}
	// 5. 乘以小数
	ret =  0.001 * float64(num)
	// 6. 保留2位小数
	ret, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", ret), 64)
	return ret
}

// 123456.78 ==> ab896745[hex]
func WriteBCDValue(val float64) []byte{
	str := fmt.Sprintf("00000000%.0f", val*100)
	str = str[len(str)-8:]
	data := utils.HexToBytes(str)
	data = utils.BytesReverse(data)
	for n, _ := range data {
		data[n] = data[n] + 0x33
	}
	return data
}

func MeterValue(bs []byte) float64 {
	// log.Println(utils.BytesToHex(bs))
	var ret float64 = 0.00
	// 1. 翻转
	data := utils.BytesReverse(bs)
	// 2. BCD转码
	for n, _ := range data {
		data[n] = data[n] - 0x33
	}
	// 3. 转hex
	valStr := utils.BytesToHex(data)
	// 4. 转整数
	num, err := strconv.Atoi(valStr)
	if err != nil {
		return ret 
	}
	// 5. 乘以小数
	ret =  0.01 * float64(num)
	// 6. 保留2位小数
	ret, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", ret), 64)

	return ret
}

func buildPacket(addr string, data []byte) []byte {
	buf := bytes.Buffer{}
	buf.WriteByte(0x68)
	buf.Write(utils.BytesReverse(utils.HexToBytes(addr)))
	buf.Write(data)
	buf.WriteByte(utils.Cs(buf.Bytes()))
	buf.WriteByte(0x16)

	return buf.Bytes()
}